﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Configuration;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;

namespace TeamFoundation.EventBus
{
    public class SubscribeAction : IAction
    {
        #region IAction Members

        public void Action(HttpContext context)
        {
            bool isInstalled = WebConfigurationManager.AppSettings["isInstalled"] == "true";
            if (!isInstalled)
            {
                context.Response.Write(
                    "TFEB is not installed. Please <a href='Install.aspx'>install</a> it.");
                return;
            }
            if (!context.User.IsInRole("Administrators"))
            {
                context.Response.Write(
                    "You do not have sufficient permissions to change subscriptions. Please return to the <a href='Default.aspx'>Deck</a>.");
                return;
            }

            string evt = context.Request.Params["event"];
            string to = context.Request.Params["to"];
            string id = context.Request.Params["id"];

            context.Response.Write(to + "ing...<br />");
            context.Response.Flush();

            try
            {
                using (TeamFoundationServer tfs = new TeamFoundationServer(WebConfigurationManager.AppSettings["tfServer"]))
                {
                    tfs.EnsureAuthenticated();
                    IEventService svc = (IEventService)tfs.GetService(typeof(IEventService));
                    if (evt == null)
                    {
                        if (!SubscribeAll(context, to, svc))
                            return;
                    }
                    else
                    {
                        if (!SubscribeNamed(context, evt, to, id, svc))
                            return;
                    }
                }

                context.Response.Redirect("Default.aspx");
            }
            catch (Exception ex)
            {
                context.Response.Write("<span style='color: red'>");
                context.Response.Write("Subscription failed: <br />");
                context.Response.Write("</span>");
                context.Response.Write(ex.ToString());
                context.Response.Flush();
            }
        }

        private bool SubscribeAll(HttpContext context, string to, IEventService svc)
        {
            bool success = true;
            if (to == "Subscribe")
            {
                DeliveryPreference pref = CreateDeliveryPreference(context);
                foreach (string evt in Utilities.GetEvents())
                {
                    try
                    {
                        svc.SubscribeEvent(null, evt, null, pref, "tfeb");
                        context.Response.Write(string.Format("Subscribed to {0}. <br/>", evt));
                    }
                    catch (Exception ex)
                    {
                        context.Response.Write("<span style='color: orange'>");
                        context.Response.Write("Subscription failed: <br />");
                        context.Response.Write("</span>");
                        context.Response.Write(ex.Message + "<br/>");
                        context.Response.Flush();
                        success = false;
                    }
                }
            }
            else
            {
                List<int> ids = new List<int>();
                foreach (Subscription sub in svc.EventSubscriptions(context.User.Identity.Name))
                {
                    if (sub.Tag == "tfeb")
                    {
                        ids.Add(sub.ID);
                    }
                }

                foreach (int id in ids)
                {
                    try
                    {
                        svc.UnsubscribeEvent(id);
                        context.Response.Write(string.Format("Unsubscribed from event {0}. <br/>", id));
                    }
                    catch (Exception ex)
                    {
                        context.Response.Write("<span style='color: orange'>");
                        context.Response.Write("Unsubscription failed: <br />");
                        context.Response.Write("</span>");
                        context.Response.Write(ex.Message + "<br/>");
                        context.Response.Flush();
                        success = false;
                    }
                }
            }
            return success;
        }

        private static bool SubscribeNamed(HttpContext context, string evt, string to, string id, IEventService svc)
        {
            bool success = false;
            if (to == "Subscribe")
            {
                DeliveryPreference pref = CreateDeliveryPreference(context);

                svc.SubscribeEvent(null, evt, null, pref, "tfeb");
                success = true;
            }
            else if (to == "Unsubscribe")
            {

                int sid;
                if (int.TryParse(id, out sid))
                {
                    svc.UnsubscribeEvent(sid);
                    success = true;
                }
                else
                {
                    context.Response.Write(
                        "Invalid request.");
                }
            }
            else
            {
                context.Response.Write(
                    "Invalid request.");
            }
            return success;
        }

        private static DeliveryPreference CreateDeliveryPreference(HttpContext context)
        {
            string localEvent = GetNotifyUrl(context);
            DeliveryPreference pref = new DeliveryPreference();
            pref.Address = localEvent;
            pref.Schedule = DeliverySchedule.Immediate;
            pref.Type = DeliveryType.Soap;
            return pref;
        }

        private static string GetNotifyUrl(HttpContext context)
        {
            return new Uri(Utilities.DiscoverRootUrl(context.Request), "./Notification.asmx").ToString();
        }

        #endregion
    }
}
